package service

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"ollama-go/dto"
	"ollama-go/entity"
	"ollama-go/query"
	"ollama-go/vo"

	"github.com/androidsr/sc-go/model"
	"github.com/androidsr/sc-go/sbuilder"
	"github.com/androidsr/sc-go/sc"
	"github.com/androidsr/sc-go/sgorm"
	"github.com/androidsr/sc-go/sno"
)

var dbDataSourceService *DbDataSourceService

type DbDataSourceService struct {
}

func NewDbDataSourceService() *DbDataSourceService {
	if dbDataSourceService == nil {
		dbDataSourceService = new(DbDataSourceService)
	}
	return dbDataSourceService
}

// 使用id获取数据
func (m DbDataSourceService) Get(id string) *vo.DbDataSourceVO {
	data := new(entity.DbDataSource)
	data.Id = id
	err := sgorm.DB.GetOne(data)
	if err != nil {
		return nil
	}
	return sc.Copy[vo.DbDataSourceVO](data)
}

// 保存数据
func (m DbDataSourceService) Save(dto *dto.DbDataSourceDTO) error {
	data := sc.Copy[entity.DbDataSource](dto)
	data.Id = sno.GetString()
	err := sgorm.DB.Insert(data)
	return err
}

// 更新数据
func (m DbDataSourceService) UpdateById(dto *dto.DbDataSourceDTO) error {
	dbEntity := new(entity.DbDataSource)
	dbEntity.Id = dto.Id
	sgorm.DB.GetOne(dbEntity)
	if dbEntity.TenantId != "" && dbEntity.TenantId != dto.TenantId {
		return errors.New("非本人创建不能修改")
	}
	sc.CopyTo(dto, dbEntity)
	err := sgorm.DB.UpdateById(dbEntity).Error
	return err
}

// 删除数据
func (m DbDataSourceService) DeleteById(id string) error {
	err := sgorm.DB.DeleteById(entity.DbDataSource{}, id)
	return err
}

// 分页列表查询
func (m DbDataSourceService) QueryPage(query *query.DbDataSourceQueryDTO) *model.PageResult {
	sql := `select * from db_data_source a `
	data := make([]entity.DbDataSource, 0)
	b := sbuilder.StructToBuilder(query, sql)
	sql, values := b.Build()
	return sgorm.DB.SelectPage(&data, query.BaseQueryDTO.Page, sql, values...)
}

// 分页下拉查询
func (m DbDataSourceService) QueryList(query *model.SelectQueryDTO) *model.PageResult {
	sql := `select a.id as value, a.dbname as label from db_data_source a where 1=1 `
	data := make([]model.SelectVO, 0)
	b := sbuilder.Builder(sql)
	b.Like("CONCAT(a.id,a.dbname)", query.Label)
	for k, v := range query.Vars {
		b.Eq(k, v)
	}
	b.Multiple().Ors(b.In("a.id", query.Selected))
	sql, values := b.Build()
	return sgorm.DB.SelectPage(&data, &query.Page, sql, values...)
}

/** 获取所有表信息 **/
func (m DbDataSourceService) GetTables(dbname string) ([]vo.TableInfo, error) {
	config := m.FindByConfig(dbname)
	db, err := m.GetConnect(config.DbType, config.Url)
	if err != nil {
		return nil, err
	}
	sql := fmt.Sprintf(`SELECT table_name as name,table_comment as table_desc  FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '%s'`, dbname)
	rows, err := db.Query(sql)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	result := make([]vo.TableInfo, 0)
	item := vo.TableInfo{}
	for rows.Next() {
		if err := rows.Scan(&item.TableName, &item.TableDesc); err != nil {
			log.Printf("获取表结构返回数据错误：%v", err)
			continue
		}
		result = append(result, item)
	}
	return result, nil
}

/** 获取表结构定义 **/
func (m DbDataSourceService) GetTableDetail(dbname string, tableNames []interface{}) (string, error) {
	config := m.FindByConfig(dbname)
	db, err := m.GetConnect(config.DbType, config.Url)
	if err != nil {
		return "", err
	}
	result := make([]string, 0)
	sql := `SHOW CREATE TABLE %s`
	for _, tableName := range tableNames {
		rows, err := db.Query(fmt.Sprintf(sql, tableName))
		if err != nil {
			log.Printf("获取表结构返回数据错误：%v", err)
			return "", err
		}
		var detail string
		for rows.Next() {
			err := rows.Scan(&tableName, &detail)
			if err != nil {
				log.Printf("获取表结构返回数据错误：%v", err)
				break
			}
			result = append(result, detail)
		}
		rows.Close()
	}
	bs, err := json.Marshal(result)
	if err != nil {
		return "", err
	}
	return string(bs), nil
}

/** 获取表结构定义 **/
func (m DbDataSourceService) QueryExecSql(dbname, sql string) (string, error) {
	log.Printf("执行数据库：%s -> %s", dbname, sql)
	config := m.FindByConfig(dbname)
	db, err := m.GetConnect(config.DbType, config.Url)
	if err != nil {
		return "", err
	}
	results, err := m.QuerySql(db, sql)
	if err != nil {
		return "", err
	}
	bs, err := json.Marshal(results)
	if err != nil {
		return "", err
	}
	return string(bs), nil
}

func (m DbDataSourceService) QuerySql(db *sql.DB, sql string) ([]map[string]string, error) {
	rows, err := db.Query(sql)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	cols, _ := rows.Columns()
	values := make([][]byte, len(cols))
	scans := make([]interface{}, len(cols))
	for i := range values {
		scans[i] = &values[i]
	}
	results := make([]map[string]string, 0)
	for rows.Next() {
		err := rows.Scan(scans...)
		if err != nil {
			return nil, err
		}
		row := make(map[string]string, 0)
		for k, v := range values {
			key := cols[k]
			row[key] = string(v)
		}
		results = append(results, row)
	}
	return results, nil
}

func (m DbDataSourceService) FindByConfig(dbname string) *entity.DbDataSource {
	data := &entity.DbDataSource{}
	data.Dbname = dbname
	err := sgorm.DB.Get(data)
	if err != nil {
		log.Printf("获取数据源失败：%v", err)
		return nil
	}
	return data
}

func (m DbDataSourceService) GetConnect(dbtype string, url string) (*sql.DB, error) {
	db, err := sql.Open(dbtype, url)
	if err != nil {
		return nil, err
	}
	return db, nil
}
